package com.soul.doc.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.soul.common.bean.comm.BasePo;
import com.soul.common.bean.vo.BaseDataVo;
import com.soul.common.bean.vo.FileVo;
import com.soul.common.exception.BaseException;
import com.soul.common.service.BaseDataService;
import com.soul.common.utils.ListUtil;
import com.soul.common.utils.RedisCache;
import com.soul.doc.bean.dto.CollectionDto;
import com.soul.doc.bean.dto.SongListAddDto;
import com.soul.doc.bean.dto.SongListSearchDto;
import com.soul.doc.bean.dto.SongListUpdateDto;
import com.soul.doc.bean.po.LoveSongListPo;
import com.soul.doc.bean.po.MusicPo;
import com.soul.doc.bean.po.SongListMusicPo;
import com.soul.doc.bean.po.SongListPo;
import com.soul.doc.bean.vo.MusicVo;
import com.soul.doc.bean.vo.SongListVo;
import com.soul.doc.mapper.SongListMapper;
import com.soul.doc.service.*;
import com.soul.common.service.BaseService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Optional;

/**
 * <p>
 * 歌单表 服务实现类
 * </p>
 *
 * @author sws
 * @since 2023-11-27 23:13:16
 */
@Service
public class SongListServiceImpl extends BaseService<SongListMapper, SongListPo> implements SongListService {

    @Autowired
    private BaseDataService baseDataService;
    @Autowired
    private RedisCache redisCache;
    @Autowired
    private LoveSongListService loveSongListService;
    @Autowired
    private LoveMusicService loveMusicService;
    @Autowired
    private SongListMusicService songListMusicService;
    @Autowired
    private MusicService musicService;
    @Override
    public IPage<SongListVo> querySongList(Integer page, Integer size, SongListSearchDto searchDto){
        LambdaQueryWrapper<SongListPo> wrapper = this.lambadaQueryWrapper();

        if (ObjectUtil.isNotEmpty(searchDto)){
            wrapper.like(ObjectUtil.isNotEmpty(searchDto.getName()),SongListPo::getName,searchDto.getName())
                    .orderByDesc(ObjectUtil.equals(searchDto.getSortType(),"hot"),SongListPo::getCollectNum);
        }
        Page<SongListPo> userPoPage = this.page(new Page<>(page, size), wrapper);
        BaseDataVo baseDataVo = baseDataService.loadBaseData(userPoPage.getRecords(), (t, b) -> {
            b.addFileId(t.getPicFileId()).addUserId(t.getCreateUser());
        });
        IPage<SongListVo> convert = userPoPage.convert(t->this.toDataVo(t,baseDataVo));
        return convert;
    }

    private SongListVo toDataVo(SongListPo po,BaseDataVo baseDataVo){
        SongListVo songListVo = BeanUtil.copyProperties(po, SongListVo.class);
        FileVo fileVo = baseDataVo.getFileVo(po.getPicFileId());
        if (ObjectUtil.isNotEmpty(fileVo)){
            songListVo.setPicFileVo(fileVo);
            songListVo.setPicUrl(fileVo.getUrl());
        }
        songListVo.setCreateUserVo(baseDataVo.getUserVo(po.getCreateUser()));
        return songListVo;
    }
    private SongListVo toDataVo(SongListPo po){
        BaseDataVo baseDataVo = new BaseDataVo();
        baseDataVo.addFileId(po.getPicFileId())
                .addUserId(po.getCreateUser());
        baseDataService.loadBaseData(baseDataVo);
        return toDataVo(po,baseDataVo);
    }

    /**
     * 用户新增歌单
     */
    @Override
    public void addSongListByUser(SongListAddDto addDto){
        SongListPo po = new SongListPo();
        po.setName(addDto.getName()).setPicFileId(addDto.getPicFileId());
        // 排序
        Long userId = StpUtil.isLogin() ? StpUtil.getLoginIdAsLong() : 100L;
        Long maxSort = this.getMaxSort(SongListPo::getCreateUser, userId);
        po.setSort(maxSort);
        po.setCollectNum(0);
        po.setPlayNum(0);
        this.save(po);
    }

    @Override
    public void updateSongListByUser(SongListUpdateDto updateDto){
        SongListPo po = this.getById(updateDto.getId());
        BeanUtil.copyProperties(updateDto,po);
        this.updateById(po);
    }

    /**
     * 删除歌单
     * @param ids
     */
    @Override
    public void deleteSongList(List<Long> ids){
        long id = StpUtil.getLoginIdAsLong();
        if (ObjectUtil.isNotEmpty(id)){
            throw new BaseException("请重新登录！");
        }
        List<SongListPo> list = this.getLambadaQueryWrapper().eq(SongListPo::getCreateUser, id).in(BasePo::getId, ids).list();
        List<Long> newIds = ListUtil.toValueList(list, BasePo::getId);
        this.removeByIds(newIds);
    }

    @Override
    public List<SongListVo> queryMySongList(){
        if (!StpUtil.isLogin()){
            throw new BaseException("未登录");
        }
        long id = StpUtil.getLoginIdAsLong();
        List<SongListVo> retList = new ArrayList<>();
        // 添加我喜欢
        SongListVo songListVo = new SongListVo();
        songListVo.setId(0L);
        songListVo.setName("我喜欢");
        // 查询我喜欢的歌曲
        List<MusicVo> musicVos = musicService.queryLoveMusic();
        songListVo.setMusicList(musicVos);
        songListVo.setMusicNum(musicVos.size());
        if (ObjectUtil.isNotEmpty(musicVos)){
            songListVo.setPicUrl(musicVos.get(0).getPicUrl());
        }
        retList.add(songListVo);
        // 当前登录人
        List<SongListPo> mySong = this.getLambadaQueryWrapper().eq(BasePo::getCreateUser, id).orderByDesc(BasePo::getSort).list();
        BaseDataVo baseDataVo = baseDataService.loadBaseData(mySong, (t, b) -> {
            b.addFileId(t.getPicFileId()).addUserId(t.getCreateUser());
        });
        retList.addAll(ListUtil.toValueList(mySong,t->this.toDataVo(t,baseDataVo)));
        return retList;
    }

    public List<SongListVo> querySongListByIds(Collection<Long> ids){
        if (ObjectUtil.isEmpty(ids)){
            return new ArrayList<>();
        }
        List<SongListPo> songListPos = this.listByIds(ids);
        BaseDataVo baseDataVo = baseDataService.loadBaseData(songListPos, (t, b) -> {
            b.addFileId(t.getPicFileId()).addUserId(t.getCreateUser());
        });
        return ListUtil.toValueList(songListPos,t->this.toDataVo(t,baseDataVo));
    }
    @Override
    public List<SongListVo> queryMyLoveList() {
        List<LoveSongListPo> loveSongList = loveSongListService.getLoveSongList();
        if (ObjectUtil.isEmpty(loveSongList)){
            return new ArrayList<>();
        }
        List<Long> listIds = ListUtil.toValueList(loveSongList, LoveSongListPo::getSongListId);
        return this.querySongListByIds(listIds);
    }

    @Override
    public void addLove(CollectionDto collectionDto) {
        boolean b = loveSongListService.addLoveSongList(collectionDto);
        if (b){
            // 收藏成功，数量+1
            this.addCollectNum(collectionDto.getSongListId(),collectionDto.getType());
        }
    }

    @Override
    public void addMusic(CollectionDto collectionDto) {
        if (!StpUtil.isLogin()){
            throw new BaseException("未登录");
        }
        boolean isAdd = false;
        long userId = StpUtil.isLogin() ? StpUtil.getLoginIdAsLong() : 100L;
        Long songListId = collectionDto.getSongListId();
        if (!ObjectUtil.equals(0L,songListId)){
            SongListPo songListPo = this.getById(songListId);
            Long createUser = songListPo.getCreateUser();
            if (!ObjectUtil.equals(createUser,userId)){
                throw new BaseException("只能添加自己的歌单！");
            }
            isAdd = songListMusicService.addSongListMusic(collectionDto);
        }else {
            isAdd = loveMusicService.addLoveMusic(collectionDto);
        }
        if (isAdd){
            // 歌曲收藏数+1
            musicService.addCollectNum(collectionDto.getMusicId(), collectionDto.getType());
        }
    }

    @Override
    public SongListVo getInfoById(Long id){
        if (ObjectUtil.equals(0L,id)){
            // 我喜欢
            List<MusicVo> musicVos = musicService.queryLoveMusic();
            SongListVo songListVo = new SongListVo();
            songListVo.setId(0L);
            songListVo.setName("我喜欢");
            songListVo.setMusicList(musicVos);
            songListVo.setMusicNum(musicVos.size());
            if (!musicVos.isEmpty()){
                MusicVo musicVo = musicVos.get(0);
                songListVo.setPicUrl(musicVo.getPicUrl());
            }
            return songListVo;
        }
        SongListPo listPo = this.getById(id);
        if (ObjectUtil.isEmpty(listPo)){
            throw new BaseException("歌单已被删除");
        }
        List<SongListMusicPo> songListMusicPos = songListMusicService.querySongListMusics(id);
        SongListVo dataVo = this.toDataVo(listPo);
        List<Long> musicIds = ListUtil.toValueList(songListMusicPos, SongListMusicPo::getMusicId);
        if (ObjectUtil.isNotEmpty(musicIds)){
            List<MusicVo> musicVos = this.musicService.queryMusicByIds(musicIds);
            dataVo.setMusicList(musicVos);
        }
        // 判断歌单是否已经收藏
        if (StpUtil.isLogin()){
            boolean isLove = loveSongListService.isSongListLove(id);
            dataVo.setIsLove(isLove?1:0);
        }
        return dataVo;
    }

    @Override
    public synchronized void addPlayNum(Long songListId){
        if (songListId == 0L){
            // 歌单为我喜欢
            return;
        }
        SongListPo songListPo = this.getById(songListId);
        if (ObjectUtil.isEmpty(songListPo)){
            throw new BaseException("歌单不存在！");
        }
        Integer playNum = Optional.of(songListPo.getPlayNum()).orElse(0) + 1;
        this.lambdaUpdate().set(SongListPo::getPlayNum,playNum).eq(SongListPo::getId,songListId).update();
    }
    @Override
    public synchronized void addCollectNum(Long songListId,String type){
        if (songListId == 0L){
            // 歌单为我喜欢
            return;
        }
        SongListPo songListPo = this.getById(songListId);
        if (ObjectUtil.isEmpty(songListPo)){
            throw new BaseException("歌单不存在！");
        }
        Integer collectNum = Optional.of(songListPo.getCollectNum()).orElse(0);
        if (ObjectUtil.equals(type,"remove")){
            collectNum = collectNum > 0 ? collectNum - 1 : 0;
        }else {
            collectNum++;
        }
        this.lambdaUpdate().set(SongListPo::getCollectNum,collectNum).eq(SongListPo::getId,songListId).update();
    }
}
